export function noop(...args:any[]) {
  false && console.log(args)
}

export function throttle (func:any, wait:any, options?:any) {
  let context:any
  let args:any
  let result:any;
  let timeout:any = null;
  // 上次执行时间点
  let previous = 0;
  if (!options) {
    options = {};
  }
  // 延迟执行函数
  function later() {
    // 若设定了开始边界不执行选项，上次执行时间始终为0
    previous = options.leading === false ? 0 : new Date().getTime();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) {
      context = args = null;
    }
  };
  return function() {
    const now = new Date().getTime();
    // 首次执行时，如果设定了开始边界不执行选项，将上次执行时间设定为当前时间。
    if (!previous && options.leading === false) {
      previous = now;
    }
    // 延迟执行时间间隔
    const remaining = wait - (now - previous);
    context = this;
    args = arguments;
    // 延迟时间间隔remaining小于等于0，表示上次执行至此所间隔时间已经超过一个时间窗口
    // remaining大于时间窗口wait，表示客户端系统时间被调整过
    if (remaining <= 0 || remaining > wait) {
      clearTimeout(timeout);
      timeout = null;
      previous = now;
      result = func.apply(context, args);
      if (!timeout) {
        context = args = null;
      }
    // 如果延迟执行不存在，且没有设定结尾边界不执行选项
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
    return result;
  };
};

export function debounce(func:any, wait:any, immediate:any):(...args:any[]) => any {
  let timeout:any
  let args:any
  let context:any
  let timestamp:any
  let result:any;

  function later() {
    // 据上一次触发时间间隔
    const last = new Date().getTime() - timestamp;

    // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout){
          context = args = null;
        }
      }
    }
  };

  return function() {
    context = this;
    args = arguments;
    timestamp = new Date().getTime();
    const callNow = immediate && !timeout;
    // 如果延时不存在，重新设定延时
    if (!timeout) {
      timeout = setTimeout(later, wait);
    }
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
};

export function getValueFromObject(object:object, key:string, defaultValue?:any) {
  try {
    noop(object)
    return eval(`object.${key}`);
  } catch (error) {
    if (defaultValue) {
      return defaultValue
    }
    throw error
  }
}